#pragma once

#include <iostream>
#include <string>
#include <cstdio>
#include <set>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Inet_Addr.hpp"
#include "Log.hpp"

using namespace LogModule;

class Command
{
private:
    std::string Execute(const std::string &cmdstr)
    {
        if(!IsSafeCommand(cmdstr))
        {
            return "unsafe";
        }
        std::string result;
        FILE *fp = popen(cmdstr.c_str(), "r");
        if (fp)
        {
            char line[1024];
            while (fgets(line, sizeof(line), fp))
            {
                result += line;
            }
            return result.empty() ? "success" : result;
        }
        pclose(fp);
        return "exexute error";
    }

    bool IsSafeCommand(const std::string& cmdstr)
    {
        for(auto & cmd : _safe_command)
        {
            if(strncmp(cmd.c_str(), cmdstr.c_str(), cmd.size()))
            {
                return true;
            }
        }

        return false;
    }

public:
    Command()
    {
        _safe_command.insert("ls");
        _safe_command.insert("touch"); // touch filename
        _safe_command.insert("pwd");
        _safe_command.insert("whoami");
        _safe_command.insert("which"); // which pwd
    }
    ~Command()
    {
    }

    void HandlerCommand(int sockfd, Inet_Addr addr)
    {
        while (true)
        {
            char comBuffer[1024];
            // 读取指令字符串
            ssize_t n = ::recv(sockfd, comBuffer, sizeof(comBuffer) - 1, 0);
            if (n > 0)
            {
                comBuffer[n] = 0;
                LOG(INFO, "get command from client: %s, command is : %s\n", addr.AddrStr().c_str(), comBuffer);
                std::string result = Execute(comBuffer);// 处理命令
                ::send(sockfd, result.c_str(), result.size(), 0);// 返回给客户端
            }
            else if (n == 0)
            {
                LOG(INFO, "client %s quit\n", addr.AddrStr().c_str());
                break;
            }
            else
            {
                LOG(FATAL, "%s read error\n", addr.AddrStr().c_str());
                break;
            }
        }
    }

private:
    std::set<std::string> _safe_command; // 安全指令
};
